(function () {
    ko.simpleGrid = {

        // Defines a view model class you can use to populate a grid
        viewModel: function (configuration) {
            /************************
            Private Functions
            ************************/
            function setTHClass(event) {
                //remove the existing classes
                $("th.head").find(".sort_wrapper").children("span").removeClass("asc");
                $("th.head").find(".sort_wrapper").children("span").removeClass("desc");
                var links = document.getElementsByTagName("th");

                $("th.head").each(function (i) {
                    links[i].onclick = function () {
                        //alert('sort order: ' + this.sortOrder);
                        if (this.sortOrder === "asc") {
                            $(this).find("span").addClass("asc");
                            this.sortOrder = "desc";
                        } else {
                            $(this).find("span").addClass("desc");
                            this.sortOrder = "asc";
                        }
                    }
                });
            }

            function switchSortOrder() {
                if (this.sortOrder === "asc") {
                    this.sortOrder = "desc";
                } else {
                    this.sortOrder = "asc";
                }
            }
            function SetOrder(event, colName) {
                switchSortOrder();
                setTHClass(event);
                if (colName != "")
                    this.data(SortByPropertyName(ko.utils.unwrapObservable(this.data()), colName, sortOrder));
            }

            // sort all items
            function SortByPropertyName(items, propertyName, sortOrder) {
                return items.sort(sortProperty(propertyName, sortOrder));
            }
            function sortProperty(property, sortOrder) {
                if (sortOrder == "asc")
                    return function (a, b) {
                    	var number = parseFloat(a[property].toLowerCase());
                        if (number != NaN && number > 0)
                        	return (parseFloat(a[property].toLowerCase()) < parseFloat(b[property].toLowerCase())) ? -1 : (parseFloat(a[property].toLowerCase()) > parseFloat(b[property].toLowerCase())) ? 1 : 0;
                        else
                        	return (a[property].toLowerCase() < b[property].toLowerCase()) ? -1 : (a[property].toLowerCase() > b[property].toLowerCase()) ? 1 : 0;
                    }
                else
                    return function (a, b) {
                    	var number = parseFloat(a[property].toLowerCase());
                        if (number > 0)
                        	return (parseFloat(a[property].toLowerCase()) > parseFloat(b[property].toLowerCase())) ? -1 : (parseFloat(a[property].toLowerCase()) < parseFloat(b[property].toLowerCase())) ? 1 : 0;
                        else
                        	return (a[property].toLowerCase() > b[property].toLowerCase()) ? -1 : (a[property].toLowerCase() < b[property].toLowerCase()) ? 1 : 0;
                    }

            }


            this.SetOrder = SetOrder;
            this.colName = "";
            this.sortOrder = ko.observable("asc");
            this.data = ko.observableArray(configuration.data);
            this.currentPageIndex = ko.observable(1);
            this.pageSize = ko.observable(parseInt(configuration.pageSize || 5));
            this.previousText = ko.observable("Previous");
            this.nextText = ko.observable("Next");

            // If you don't specify columns configuration, we'll use scaffolding
            this.columns = configuration.columns;

            this.maxPageIndex = ko.computed(function () {
                return Math.ceil(ko.utils.unwrapObservable(this.data()).length / this.pageSize());
            }, this);

            this.itemsOnCurrentPage = ko.computed(function () {
                var currentPage = this.currentPageIndex();
                var maxPage = this.maxPageIndex();

                if (parseInt(currentPage) == 0)
                    this.currentPageIndex(1);

                if (parseInt(currentPage) >= parseInt(maxPage)) {
                    this.currentPageIndex(parseInt(maxPage));
                }

                var startIndex = this.pageSize() * (this.currentPageIndex() - 1);
                var endIndex = parseInt(startIndex) + parseInt(this.pageSize());

                return this.data().slice(startIndex, endIndex);


            }, this);

            this.previousClass = ko.computed(function () {
                var currentPage = this.currentPageIndex();
                if (parseInt(currentPage) == 0 || parseInt(currentPage) == 1)
                    return "disable";
                else
                    return "";
            }, this);

            this.nextClass = ko.computed(function () {
                var currentPage = this.currentPageIndex();
                var maxPage = this.maxPageIndex();

                if (parseInt(currentPage) >= parseInt(maxPage))
                    return "disable";
                else
                    return "";
            }, this);

        }
    };

    

    // Templates used to render the grid
    var templateEngine = new ko.nativeTemplateEngine();

    templateEngine.addTemplate = function (templateName, templateMarkup) {
        document.write("<script type='text/html' id='" + templateName + "'>" + templateMarkup + "<" + "/script>");
    };

    var gridHeader = "<div class=\"header\">";
    gridHeader += "<span class=\"left\">";
    gridHeader += "<input onkeypress='return isNumberKey(event)' data-bind=\"value: pageSize, attr:{type: 'text', maxlength: 2} \" /> / Page";
    gridHeader += "</span>";

    gridHeader += "<span class=\"right\">";
    gridHeader += "<a href=\"##\" data-bind=\"text: previousText, click: function() { $root.currentPageIndex(currentPageIndex() - 1) }, attr: {class: previousClass} \">Previous</a>";
    gridHeader += "<input onkeypress='return isNumberKey(event)' data-bind=\"value: currentPageIndex, attr: {type: 'text', maxlength: 2} \" /> of <span data-bind=\"text: maxPageIndex() \"></span>";
    gridHeader += "<a href=\"##\" data-bind=\"text: nextText, click: function() { $root.currentPageIndex(currentPageIndex() + 1) } , attr: {class: nextClass} \"></a>";
    gridHeader += "</span>";
    gridHeader += "</div>";

    templateEngine.addTemplate("ko_simpleGrid_pageLinks", gridHeader);

    templateEngine.addTemplate("ko_simpleGrid_grid", "\
                    <table width=\"100%\"  class=\"tablegrid\" cellspacing=\"0\">\
                        <thead>\
                            <tr class='title' data-bind=\"foreach: columns\">\
                               <th class='head' data-bind=\"click: function(event) { $root.SetOrder(event, columName) } \">\
                                 <div class=\"sort_wrapper\"><font data-bind=\"text: headerText \"></font> <span class='grid_order ui_icon'></span></div>\
                               </th>\
                            </tr>\
                        </thead>\
                        <tbody data-bind=\"foreach: itemsOnCurrentPage\">\
                           <tr class='line' data-bind=\"foreach: $parent.columns\">\
                               <td data-bind=\"html: typeof rowText == 'function' ? rowText($parent) : $parent[rowText] \"></td>\
                            </tr>\
                        </tbody>\
                    </table>");

    // The "simpleGrid" binding
    ko.bindingHandlers.simpleGrid = {
        init: function () {
            return { 'controlsDescendantBindings': true };
        },
        // This method is called to initialize the node, and will also be called again if you change what the grid is bound to
        update: function (element, viewModelAccessor, allBindingsAccessor) {
            var viewModel = viewModelAccessor(), allBindings = allBindingsAccessor();

            // Empty the element
            while (element.firstChild)
                ko.removeNode(element.firstChild);

            // Allow the default templates to be overridden
            var gridTemplateName = allBindings.simpleGridTemplate || "ko_simpleGrid_grid",
                pageLinksTemplateName = allBindings.simpleGridPagerTemplate || "ko_simpleGrid_pageLinks";

            // Render the page links
            var pageLinksContainer = element.appendChild(document.createElement("DIV"));
            ko.renderTemplate(pageLinksTemplateName, viewModel, { templateEngine: templateEngine }, pageLinksContainer, "replaceNode");

            // Render the main grid
            var gridContainer = element.appendChild(document.createElement("DIV"));
            ko.renderTemplate(gridTemplateName, viewModel, { templateEngine: templateEngine }, gridContainer, "replaceNode");
        }
    };
})();